﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using com.yoozoo.gta.Gameplay.RTS;
using com.youzu.warh.protocol;
using ProtoBuf;
using UnityEngine;
using UnityEngine.Networking;
using Yoozoo.External.LZ4;
using Yoozoo.Libs;

namespace Yoozoo.Gameplay.RTS
{
    public class RtsArenaReportManager
    {
        public string reportId;
        public bool needJumpToCurrentTime = false;


        private ReportRequester reportRequester;
        
        public void Initialize()
        {
            reportRequester = new ReportRequester();
            reportRequester.SetHandler(DeserializeArenaBattleReport,OnGetReport,OnGetReportFailed);
        }
        

        public void Restart()
        {
            reportRequester.Restart();
        }
        
        
        public void RequestReport(string url)
        {
            reportRequester.RequestReport(url);
        }

        public void Update()
        {
            reportRequester?.Update();
        }

        private void OnGetReportFailed(bool timeout = false)
        {
            RtsArenaManager.Instance.OnGetReportFailed(timeout);
        }
        
        [Serializable]
        private class ReportFile
        {
            public string data;
            public int status;
        }
        
        public ArenaBattleReport DeserializeArenaBattleReport(byte[] message)
        {
            if (Debug.isDebugBuild)
            {
                Debug.Log("[RTS竞技场]战报长度："+(message.Length / 1024).ToString("0.0")+" kb");
            }
            var jsonString = Encoding.UTF8.GetString(message);
            var reportFile = JsonUtility.FromJson<ReportFile>(jsonString);
            if (reportFile == null)
            {
                Debug.LogError("[RTS竞技场]战报Json解析错误");
                return null;
            }

            if (reportFile.status != 0)
            {
                Debug.LogError("[RTS竞技场]战报请求出错，status = " + reportFile.status);
                return null;
            }

            if (reportFile.data == null)
            {
                Debug.LogError("[RTS竞技场]战报data为空："+jsonString);
                return null;
            }
            var data = Convert.FromBase64String(reportFile.data);
            try
            {
                int decodeLen = Converter.GetBigEndian(BitConverter.ToInt32(data, 0));
                var msgLen = data.Length - 4;
                byte[] proto = null;
                if (decodeLen == 0)
                {
                    int protoLen = msgLen;
                    proto = new byte[protoLen];
                    Array.Copy(data, 4, proto, 0, protoLen);
                }
                else
                {
                    int decodeLength = msgLen;
                    byte[] outPutBytes = new byte[decodeLen];
                    if (LZ4Codec.Decode(data, 4, decodeLength, outPutBytes, 0,
                            decodeLen) == decodeLen)
                    {
                        proto = outPutBytes;
                    }
                    else
                    {
                        UnityEngine.Debug.LogErrorFormat("<color=red> LZ4Codec.Decode failed!!!</color>");
                    }
                }

                if (proto != null)
                {
                    using (MemoryStream ms = new MemoryStream(proto))
                    {
                    
                        ArenaBattleReport report = ProtoBufSerializer.Deserialize(ms,typeof(ArenaBattleReport),proto.Length) as ArenaBattleReport;
                        if (report != null)
                        {
                            if (Debug.isDebugBuild)
                            {
                                LogSummary(report.reportSummary);
                                LogContent(report.reportContent);
                            }
                            //AddToCache(reportUrl,report);
                            ProcessReport(report);
                        }
                        else
                        {
                            Debug.LogError("[RTS竞技场]战报Proto解析错误:\n"+reportFile.data);
                        }
#if UNITY_EDITOR
                        /*FileStream fs = new FileStream(System.Environment.CurrentDirectory  + "/Caches/" + reportId + ".txt", FileMode.Create);
                        fs.Write(Encoding.UTF8.GetBytes(jsonString), 0, jsonString.Length);
                        fs.Close();*/
#endif
                        return report;
                    }
                }
            }
            catch (Exception e)
            {
                Debug.LogError("[RTS竞技场]战报Proto解析过程中报错:\n"+reportFile.data);
                Debug.LogError(e.ToString());
#if UNITY_EDITOR
                /*FileStream fs = new FileStream(System.Environment.CurrentDirectory  + "/Caches/ERROR_" + reportId + ".txt", FileMode.Create);
                fs.Write(Encoding.UTF8.GetBytes(jsonString), 0, jsonString.Length);
                fs.Close();*/
#endif
            }
            return null;
        }

        private void OnGetReport(object data)
        {
            var report = (ArenaBattleReport) data;
            if (report != null)
            {
                RtsArenaManager.Instance.OnReportReady(report);
            }
            else
            {
                Debug.LogError("强制转换失败");
            }
        }
        
        //处理坐标，处理左右转换
        private void ProcessReport(ArenaBattleReport report)
        {
            if (report.reportSummary != null && report.reportContent != null)
            {
                bool needReverse = report.reportSummary.rightCamp.campId == RtsArenaManager.Instance.playerId;
                if (needReverse)
                {
                    //先交换敌我双方的阵营位置
                    var temp = report.reportSummary.leftCamp;
                    report.reportSummary.leftCamp = report.reportSummary.rightCamp;
                    report.reportSummary.rightCamp = temp;
                }
                var keyFrames = report.reportContent.keyFrame;
                if (keyFrames != null)
                {
                    for (int i = 0; i < keyFrames.Count; i++)
                    {
                        var frame = keyFrames[i];
                        var pathList = frame.pathList;
                        if (pathList != null)
                        {
                            for (int j = 0; j < pathList.Count; j++)
                            {
                                pathList[j] = MarchHelper.TransformArenaCoordinate(pathList[j], needReverse);
                            }
                        }

                        if (needReverse && frame.besiegeFinalAngle >= 0)
                        {
                            frame.besiegeFinalAngle = 180 - frame.besiegeFinalAngle;
                        }
                    }
                }

                var roundFights = report.reportContent.roundFight;
                if (roundFights != null)
                {
                    for (int i = 0; i < roundFights.Count; i++)
                    {
                        var roundFight = roundFights[i];
                        var fightInfo = roundFight.fightInfo;
                        if (fightInfo != null)
                        {
                            for (int j = 0; j < fightInfo.Count; j++)
                            {
                                fightInfo[j].coordinate = MarchHelper.TransformArenaCoordinate(fightInfo[j].coordinate, needReverse);
                            }
                        }

                        var skills = roundFight.skills;
                        if (skills != null)
                        {
                            for (int j = 0; j < skills.Count; j++)
                            {
                                skills[j].attackCoordinate = MarchHelper.TransformArenaCoordinate(skills[j].attackCoordinate, needReverse);
                                skills[j].targetCoordinate = MarchHelper.TransformArenaCoordinate(skills[j].targetCoordinate, needReverse);
                            }
                        }

                        var siegeFightInfo = roundFight.siegeFightInfo;
                        if (siegeFightInfo != null)
                        {
                            for (int j = 0; j < siegeFightInfo.Count; j++)
                            {
                                siegeFightInfo[j].coordinate = MarchHelper.TransformArenaCoordinate(siegeFightInfo[j].coordinate, needReverse);
                            }
                        }
                    }
                }
            }
        }
        
        private void LogContent(ArenaReportContent content)
        {
            var log = "[RTS竞技场]Content:\n";
            Debug.Log(log);
            log = "[RTS竞技场]KeyFrame:\n";
            for (int i = 0; i < content.keyFrame.Count; i++)
            {
                log += LogKeyFrame(content.keyFrame[i]);
            }
            Debug.Log(log);
            log = "[RTS竞技场]RoundFight:\n";
            for (int i = 0; i < content.roundFight.Count; i++)
            {
                log += LogRoundFight(content.roundFight[i]);
            }
            Debug.Log(log);
        }

        private string LogRoundFight(SCRoundFight roundFight)
        {
            var log = "\tSCRoundFight:\n";
            log += "\t\tFightFrameTime: " + roundFight.fightFrameTime;
            log += "\n";
            log += "\t\tFightInfo: \n";
            if (roundFight.fightInfo != null)
            {
                for (int i = 0; i < roundFight.fightInfo.Count; i++)
                {
                    log += "\t\t\tTroopId: " + roundFight.fightInfo[i].troop.uid;
                    log += "\n";
                    log += "\t\t\tElements: \n";
                    for (int j = 0; j < roundFight.fightInfo[i].elements.Count; j++)
                    {
                        if (roundFight.fightInfo[i].elements[j].source != null)
                        {
                            log += "\t\t\t\tSource: " + roundFight.fightInfo[i].elements[j].source.uid;
                            log += "\n";
                        }
                        log += "\t\t\t\tAmount: " + roundFight.fightInfo[i].elements[j].amount;
                        log += "\n";
                    }

                    log += "\t\t\tRage: " + roundFight.fightInfo[i].rage;
                    log += "\n";
                    log += "\t\t\tRageIndex: " + roundFight.fightInfo[i].rageHeroIndex;
                    log += "\n";
                }
            }
            log += "\n";
            return log;
        }
        
        private string LogKeyFrame(TroopMarchKeyFrame keyFrame)
        {
            var log = "\tKeyFrame:\n";
            log += "\t\tLastFrameTime: " + keyFrame.lastFrameTime;
            log += "\n";
            log += "\t\tTroopId: " + keyFrame.troopId;
            log += "\n";
            log += "\t\tModifyFlag: " + Convert.ToString (keyFrame.modifyFlag, 2);
            log += "\n";
            log += "\t\tTargetId: " + keyFrame.targetId;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 4))
            {
                log += "(✔)";
            }
            log += "\n";
            if (keyFrame.attackTarget != null)
            {
                log += "\t\tAttackTargetId: " + keyFrame.attackTarget.uid;
                if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 8))
                {
                    log += "(✔)";
                }
                log += "\n";
            }
            log += "\t\tMarchStatus: " + keyFrame.marchStatus;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 6))
            {
                log += "(✔)";
            }
            log += "\n";
            if (keyFrame.pathList != null)
            {
                log += "\t\tPathList: ";
                if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 9))
                {
                    log += "(✔)";
                }
                log += "\n";
                for (int i = 0; i < keyFrame.pathList.Count; i++)
                {
                    log += string.Format("\t\t\t({0},{1})",keyFrame.pathList[i].xAxis,keyFrame.pathList[i].zAxis);
                    log += "\n";
                }
            }
            log += "\t\tBesiegeFinalAngle: " + keyFrame.besiegeFinalAngle;
            if (RtsConvertDataFactory.IsFieldModified(keyFrame.modifyFlag, 7))
            {
                log += "(✔)";
            }
            log += "\n";
            return log;
        }
        
        private void LogSummary(ArenaReportSummary summary)
        {
            var content = "[RTS竞技场]report summary:\n";
            content += LogCamp(summary.leftCamp);
            content += "\n";
            content += LogCamp(summary.rightCamp);
            Debug.Log(content);
        }

        private string LogCamp(ArenaBattleCamp camp)
        {
            var content = "reportCamp:\n";
            content += "\tCampId: " + camp.campId;
            content += "\n";
            content += "\tPlayerInfo: " + camp.playerInfo.nickname;
            content += "\n";
            content += "\tTroops: ";
            content += "\n";
            if (camp.troops != null)
            {
                for (int i = 0; i < camp.troops.Count; i++)
                {
                    var troop = camp.troops[i];
                    content += "\t\tTroopId: " + troop.troopId;
                    content += "\n";
                    content += "\t\t\tPositionId: " + troop.initPos;
                    content += "\n";
                    content += "\t\t\tSoldierId: " + troop.soldier.key;
                    content += "\n";
                    content += "\t\t\tSoldierCount: " + troop.soldier.value;
                    content += "\n";
                }
            }
            content += "\tPower: " + camp.teamPower;
            content += "\n";
            return content;
        }
        
    }
}
